package com.cy.pj.common.config;

import org.apache.shiro.mgt.RememberMeManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;

/**
 * @Author Yu
 * @create 2025/06/11
 * @description
 */
@Configuration
/*声明当前类是一个配置类 并将其交给spring管理*/
public class SpringShiroConfig {

    /**
     *  构建并初始化SecurityManager对象，然后将此对象交给spring管理，
     * 说明：@Bean注解应用于@Configuration注解描述类的内部，通过此注解描述的方法，
     * 方法的返回值会交给spring管理，默认bean的名字为方法名。
     * @return 返回值shiro中的安全管理对象，是shiro框架的核心，此对象中提供了认证，
     *          授权，会话，缓存，加密等一系列功能的实现
     */
    @Bean
    public SecurityManager securityManager(Realm realm, RememberMeManager rememberMeManager){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(realm);
        securityManager.setRememberMeManager(rememberMeManager);
        return securityManager;
    }


    /*
   配置advisor对象,shiro框架底层会通过此对象的matchs方法返回值(类似切入点)
   决定是否创建代理对象,进行权限控制
   配置授权对应的Advisor对象，此对象会在spring启动时加载，并且通过此对象找到
   @RequiresPermissioins注解描述的方法，然后这些方法在运行时，由此Advisor
   对象，调用SecurityManager中的checkPermissions方法，检查用户权限，
   并为访问目标切入点方法的用户做授权操作。
    */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(
            SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }

    @Bean
    public RememberMeManager rememberMeManager() {
        CookieRememberMeManager cManager = new CookieRememberMeManager();
        SimpleCookie cookie=new SimpleCookie("rememberMe");
        cookie.setMaxAge(7*24*60*60);//假如不设置最大时长，默认为会话Cookie
        cManager.setCookie(cookie);
        //备注：不能解密cookie时，添加此行代码。 //cookieRememberMeManager.setCipherKey(Base64.decode("6ZmI6I2j5Y+R5aSn5ZOlAA=="));
        return cManager;
    }

    /**
     * 构建并初始化ShiroFilterFactoryBean对象，创建过滤器工厂，进而通过过滤器工厂创建过滤器（filter）
     *并通过过滤器对请求信息进行过滤，例如检测此请求是否需要认证或者此请求是否已经认证。
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
        ShiroFilterFactoryBean sfFactoryBean = new ShiroFilterFactoryBean();
        sfFactoryBean.setSecurityManager(securityManager);
        /*拦截之前先放行登录界面*/
        sfFactoryBean.setLoginUrl("/doLoginUI");
        /*创建LinkedHashMap对象 用来存储过滤规则 特点：有序存储数据*/
        LinkedHashMap<String,String> map = new LinkedHashMap<>();
        //静态资源允许匿名访问:"anon"
        map.put("/bower_components/**","anon");//anonymous
        map.put("/build/**","anon");
        map.put("/dist/**","anon");
        map.put("/plugins/**","anon");
        /*登录请求放行*/
        map.put("/user/doLogin","anon");
        map.put("/doLogout","logout"); //登出操作，url根据页面路径写，logout是shiro定义登出操作
        //除了匿名访问的资源,其它都要认证("authc")后访问
        map.put("/**","user");//authentication这句话必须写在匿名访问后面。filter是有过滤先后的顺序的。
        /*存储过滤规则*/
        sfFactoryBean.setFilterChainDefinitionMap(map);
        /*返回过滤器对象*/
        return sfFactoryBean;
    }




}
